package com.zhanglijie.base.sync.Lock;

import java.lang.reflect.Field;

import sun.misc.Unsafe;

/**
 * @author zhanglijie
 * @version 1.0
 * @since 1.1.0 2022/6/12 0012 19:38
 */
public class BiasedLocking {
    public boolean revokeAndRebias(MyLock myLock) throws NoSuchFieldException {
        MarkWord markWord = myLock.getMarkWord();
        long threadId = markWord.getThreadId();
        //获得偏向锁标记
        String biasedLock = markWord.getBiasedLock();
        //获得锁锁标记
        String lockFlag = markWord.getLockFlag();
        Field threadId1 = markWord.getClass()
            .getDeclaredField("threadId");
        Unsafe unsafe = Unsafe.getUnsafe();
        long offset = unsafe.objectFieldOffset(threadId1);
        long origin = unsafe.getLongVolatile(threadId1, offset);
        long curThreadId = Thread.currentThread()
            .getId();
        //可偏向
        if (threadId == -1 && (biasedLock != null && biasedLock.equals("1")) && (lockFlag != null && lockFlag.equals(
            "01"))) {
            //cas操作修改threadId
            boolean isOk = unsafe.compareAndSwapLong(markWord, offset, origin, curThreadId);
            if (isOk) {
                return true;
            }
        }
        //已经偏向了
        else if (threadId != -1 && (biasedLock != null && biasedLock.equals("1")) && (lockFlag != null
            && lockFlag.equals("01"))) {
            //如果偏向的就是自己
            if (threadId == curThreadId)
                return true;
            //如果不是当前的,撤销偏向锁  待完成
            /**
             * 撤销：这里需要判断是否执行完同步代码块 有很多工作。撤销这里就简单实现下 不一定对.因为判断线程已经
             * 执行完同步代码块这个在java很难实现
             */
            revokeBiased(myLock);
            return false;
        }
        return false;
    }

    private boolean revokeBiased(MyLock myLock) {
        //判断线程是否执行完同步代码块（这里放松下 判断线程是否存活）这个不严谨但是在java层面我目前只能想到这个方式了
        /**
         * 难点：1安全点检查    2.是否已经离开了同步代码块（拥有偏向锁的线程是否已经离开了同步代码块）
         * 所以撤销工作是非本线程执行的
         */
        boolean isAlive = false;
        MarkWord markWord = myLock.getMarkWord();
        //表示拿到偏向锁的那个线程Id
        long threadId = markWord.getThreadId();
        ThreadGroup threadGroup = Thread.currentThread()
            .getThreadGroup();
        int i = threadGroup.activeCount();
        Thread[] threads = new Thread[i];
        int enumerate = threadGroup.enumerate(threads);
        for (Thread thread : threads) {
            //此时找到拥有 偏向锁的线程依然存活
            if(thread.getId() == threadId){
                isAlive = true;
                break;
            }
        }
        //线程存活（stw)，那么此时设置成无锁状态,撤销。下次直接去升级轻量级锁
        if(isAlive){
            markWord.setBiasedLock("0");
            markWord.setLockFlag("01");
            markWord.setThreadId(-1);
           return true;
        }
        //走轻量级锁竞争吧
        return false;


    }
}
